package com.wangdong.rxjavaandroid;


import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.wangdong.rxjavaandroid.javaobserver.demo1.Course;
import com.wangdong.rxjavaandroid.javaobserver.demo1.Student;

import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;


/**
 * 创建这个类是为了 实践"给Android开发者的Rxjava详解"
 * 地址: http://gank.io/post/560e15be2dca930e00da1083
 * 本文依赖引用的是:implementation 'io.reactivex:rxjava:1.0.14' 但是最新的已经Rxjava3了
 */
public class RxjavaActivity extends AppCompatActivity {

    public static String tag = "RxjavaActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rxjava);
        //TODO 本文内容不学习使用不做运行 有些报错地方我 注释掉了只为不报错
    }
//==================下面是简介一下 Rxjava 和 常规使用异步代码 学习在后面,看不懂没关系这不是重点===========

    /**
     * 例子:假如 界面上有一个自定义图视 ImageCollectorView 控件用来显示多张图片
     * 并使用addImage(Bitmap)方法来任意添加图片,现在需要一个给出目录数组 File[] folders 每个目录下png
     * 都加载出来显示在ImagecollectiorView中,需要注意的是: 由于读取图片这个过程是一个消耗时,需要放在后台
     * 执行.而加载图片需要UI线程执行,
     */
    public void locadImage() {
        /**使用常用的方法*/
        final File[] folders = new File[]{};
        new Thread() {
            @Override
            public void run() {
                super.run();
                for (File folder : folders) {
                    File[] files = folder.listFiles();
                    for (File file : files) {
                        if (file.getName().endsWith(".png")) {
                            // final Bitmap bitmap = getBitmapFromFile(file);
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    //imageCollectorView.addImage(bitmap);
                                }
                            });
                        }
                    }
                }
            }
        }.start();

        /**使用Rxjava方法  如果看不懂也没有关系 这只是一个例子后面会说明*/

        Observable.from(folders) //被观察者,数组使用from()
                .flatMap(new Func1<File, Observable<File>>() {
                    @Override
                    public Observable<File> call(File file) {
                        return Observable.from(file.listFiles());
                    }
                }).filter(new Func1<File, Boolean>() {
            @Override
            public Boolean call(File file) {
                return file.getName().endsWith(".png");
            }
        }).map(new Func1<File, Bitmap>() {
            @Override
            public Bitmap call(File file) {
                //return getBitmapFromFile(file);
                return null;//为了不报错添加了这行代码
            }
        }).subscribeOn(Schedulers.io())
                //.observeOn(AndroidSchedulers.mainThread()) //指明线程 在主线
                .subscribe(new Action1<Bitmap>() {
                    @Override
                    public void call(Bitmap bitmap) {
                        //imageCollectorView.addImage(bitmap);
                    }
                });

        /** 看后你会觉着那简洁了,感觉很复杂啊 ! 但是当需求复杂的时候,这优势就会明显了
         *  如果需求:加载 File[]数组只选择欠十张图片,常规方式要怎么办? 如果有更多这样的要求呢?
         *          再试想一下,在这一大堆需求实现完两个月之后需要改功能,当你翻回这里看到自己当初写下的
         *          那一边缩进,能保证自己迅速看懂,而不是对着代码重新捋一遍思路
         * */
        //为了不报错添加了这行代码
        /*Observable.from(folders)
                .flatMap( (Func1) (folder) -> { Observable.from(file.listFiles()) })
                .filter((Func1) (file) -> { file.getName().endsWith(".png") })
                .map((Func1) (file) -> {  getBitmapFromFile(file)  })
                .subscribeOn(Schedulers.io())
                    //.observeOn(AndroidSchedulers.mainThread())
                .subscribe((Action1) (bitmap) -> { imageCollectorView.addImage(bitmap)
        });*/
        /**
         * 上面使用 Ratrolarmbda 表达是看其简洁许多,但是不建议现在就去学习它,原因哟两点
         * 1.Lambda 是把双刃剑,它让你代码简洁的痛是降低了代码的可读性,
         * 2.如果使用Lambda ,可能会忽略Rxjava的一些技术细节
         */
    }
//=================== 下面: Rxjava API介绍和原理简析 =================================================

    /**
     *   1.Rxjava 的异步实现, 是通过一种扩展的观者模式实现的
     *
     *   观察者模式
     *
     *    A 对象 (观察者)  B 对象 (被观察者)    B通过 注册(Register)或订阅(Subscribe)方式 绑定 A
     *    一旦B对象中属性发生改变 A对象就会收到通知
     *
     *    java 观察模式 和 一般观察者模式 例子请查看 javaobserver包下的demo2 和 demo1
     *
     *    Android 典型例子: 点击监听器 OnClickListener  ; 对于设置 OnClickListener来说,
     *    View 是被观察者 ; OnClickListener 是观察者 ;   二者通过setOnClickListener方法达成订阅关系
     *
     *    当用户点击Button->被观察者 OnClickListener->观察者 setOnClickListener()->订阅 onClick()->事件
     *    就由专用的观察者模式(例如只用于监听控件点击)转变成了通用的观察者模式
     *              Observable 被观察者  -----onEvent(params)----> Observer 观察者
     *
     *   2. 熟悉了观察者模式以后开始学习 Rxjava 观察者模式概念及其 API
     *                  而 RxJava 作为一个工具库 ,使用的就是通用形式的观察者模式
     *
     *      RxJava 有四个基本概念 Observable (可观察者,即被观察者)
     *                          Observer (观察者)
     *                          subscribe (订阅)
     *                          事件
     *             Observable 和 Observer 通过 subscribe()方法实现订阅关系
     *             从而Observable可以在需要的时候发出时间来通知Observer
     *
     *      注册(Register)或者称为订阅(Subscribe)的方式
     *
     *             onNext( )        下一个. 普通事件 相对于android 中的 onClick ( ) / onEvent( )
     *             onCompleted ( )  事件队列完结 .Rxjava不仅把每个事件单独处理, 还会把他们看做一个队列,
     *                              Rxjava 规定了,当不会再有新的 onNext ( ) 发出时,需要触发
     *                              onCompleted ( ) 方法作为标志.
     *             onError ( )      事件队列异常 .在事件处理过程中出异常时,
     *                              onError ( ) 会触发,同时队列自动终止, 不允许再有事件发出
     *
     *       注意 : 在一个正确运行的事件序列中, onCompleted ( ) 和 onError ( ) 有且只回调一个,并且是事件序列中的最后一个,
     *             需要注意的是 onCompleted和 onError 二者也是互排斥的, 即在队列中调用了其中一个.就不应该再调用另一个.
     *             基本实现
     *                 RxJava 的基本实现主要有三点 1.观察者 2 被观察者 3.订阅
     *
     *         1.创建Observer 观察者
     *
     *                             observer 即观察者 , 它决定事件触发的时候将有怎么样的行为. RxJava中的Observer接口实现方式:
     *
     *                             Observer<String> observer = new Observer() {
     *                                 @Override
     *                                 public void onCompleted()
     *                                     System.out.println("onCompleted");
     *                                 }
     *                                 @Override
     *                                 public void onError(Throwable throwable) {
     *                                     System.out.println("nError");
     *                                 }
     *                                 @Override
     *                                 public void onNext(Object o) {
     *                                     System.out.println("onNext");
     *                                 }
     *                             };
     *              除了Observer 接口之外 ,RxJava还内置了一个实现了Observer的抽象类: Subscriber , Subscriber 对 Observer接口进行了一些扩展,
     *              基本使用是一样的
     *
     *                         Subscriber<String> subscriber = new Subscriber<String>() {
     *                             @Override
     *                             public void onNext(String s) {
     *                                 System.out.println("onNext");
     *                             }
     *
     *                             @Override
     *                             public void onCompleted() {
     *                                 System.out.println("onCompleted");
     *                             }
     *
     *                             @Override
     *                             public void onError(Throwable e) {
     *                                 System.out.println("nError");
     *                             }
     *                         };
     *              实质上 , 在RxJava的 Subscribe 过程中, Observer 也总是先被转换成一个Subscriber再使用. 所以如果你只想使用
     *             基本功能, 选择Observer 和 Subscriber 是完全一样的. 它们的区别对于使用者来说主要有两点:
     *
     *                         1.onStart( ) :这是Subscriber增加的方法. 他会在Subscribe 刚开始, 而事件还未发送之前被调用, 可以
     *                                       做一些准备工作,例如数据的清零或重置.这是一个可选方法,默认情况它的实现为空,需要注意的是
     *                                       如果对准备工作的线程有要求 (例如弹出一个显示进度的对话框,这必须在主线程执行) onStart
     *                                       () 就不适用了,应为它总是在doOnSubscribe方法,具体可以在后面的文中看到.
     *
     *                         2.unsubscribe : 这是Subscriber所实现的另一个接口Subscription的方法, 用于取消订阅.在这个方法被调用
     *                                        后, Subscriber订阅者 将不再接收事件. 一般在这个方法前,可以使用 isUnsubscribed()
     *                                        先判断一下状态. unsubscribe () 这个方法很重要,应为在 Subscribe()之后, Observable
     *                                        被观察者 会持有 Subscriber 订阅者的引用,这个引用如果不能及时释放,将有内存泄漏的风险.
     *                                        所以最好保持一个原则: 要在不使用的时候尽快在合适的地方(例如 暂停onPause() ,停止onStop()
     *                                        等方法中) 调用unsubscribe() 用来解除引用关系,以避免内存泄漏的发生.
     *
     *         2.创建Observable 被观察者
     *
     *                        Observable 被观察者 ,它决定什么时候触发事件以及触发怎么样的事件.
     *                        RxJava使用 create ( ) 方法来创建一个Observable 并为它定义事件触发规则
     *                               //传入参数 OnSubscribe 对象作为参数
     *                               //OnSubscribe会被存储在返回的Observable对象中,它的作用相当于一个计划表,
     *                               //当Observable 被观察者 被订阅的时候, 对于下面代码 OnSubscrible将会被调用三次onNext( ) 和一次onCompleted( )
     *                       Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
     *                                     @Override
     *                                     public void call(Subscriber<? super String> subscriber) {
     *                                             subscriber.onNext("Hello");
     *                                             subscriber.onNext("Hi");
     *                                             subscriber.onNext("Aloha");
     *                                             subscriber.onCompleted();
     *                                     }
     *                                 });
     *                      由被观察者调用了观察者的回调方法，就实现了由被观察者向观察者的事件传递，即观察者模式。
     *
     *                                 这个例子很简单: 事件的内容是字符串, 而不是一些复杂的对象; 事件的内容是已经定好了的, 而不像有的观察者的模式一样是待确定的
     *                                 (例如网络请求的结果在请求返回之前是未知的 ); 所有事件在一瞬间被全部发送出去,而不是夹杂一些确定或不确定的时间间隔或者经过
     *                                 某种触发器来触发的. 总之, 这个例子看起来毫无使用价值. 但这是为了便于说明,实质上只要你想,各种各样的事件发送规则你都可以自己来
     *                                 写,至于具体怎么做,后面都会讲到,但是现在不行, 只有把基础原理说明白了,上层的运用才能更容易说清楚
     *
     *                           Create( ) 方法是 Rxjava最基本的创造事件序列的方法,基于这个方法, Rxjava 还提供了一些方法用来快捷创建事件队列,
     *                          例如: just ( T...) :  将传入的参数依次发送出来
     *                                                 Observable observable = Observable.just("Hello", "Hi", "Aloha");
     *                                                     // 将会依次调用：
     *                                                     // onNext("Hello");
     *                                                     // onNext("Hi");
     *                                                     // onNext("Aloha");
     *                                                     // onCompleted();
     *
     *                           from ( T[ ] ) / from ( Iterable< ? extends T> ) :将传入的数组或 Iterable 拆分成具体对象后, 依次发送出来.
     *                                                 String [ ]  words = { "Hello", "Hi" , "Aloha" };
     *                                                 Observable observable  =  Observable. from ( words );
     *
     *                          上面的 just ( T... ) 的例子和 from ( T[ ] ) 的例子, 都和之前的 create ( OnSubscribe ) 的例子是等价的.
     *
     *
     *          3. Subscribe (订阅)
     *
     *                 创建了 Observable .subscribe ( observer ) ;
     *                                  //或者
     *                       Observable .subscribe ( subscriber );
     *
     *                 可能会注意到了, subscribe ( ) 这个方法有点怪 : 它看起是 observalbe 订阅了 observer / subscriber 而不是 observer / subscriber 订阅
     *                 observalbe , 这看起来就像 杂志订阅了读者 一样颠倒了对象关系 , 这个让人读起来有点别扭,
     *
     *                 不过如果把API 设计成 observer.subscribe ( observable ) / subscriber.subscribe ( observable ) ,
     *                 虽然更加符合逻辑, 但是对于流API 的手机就造成影响了, 比较起来明显是得不偿失的,
     *
     *                 Observable.subscribe ( Subscriber ) 的内部实现是这样 ( 仅核心代码 ) :
     *                     // 注意：这不是 subscribe() 的源码，而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
     *                     // 如果需要看源码，可以去 RxJava 的 GitHub 仓库下载。
     *                     public Subscription subscribe(Subscriber subscriber) {
     *                            subscriber.onStart(    );
     *                            onSubscribe.call ( subscriber );
     *                            return subscriber;
     *                     }
     *                可以看到 , subscriber ( ) 做了3 件事:
     *                     1.调用Subscrber .onStart ( ) . 这个方法在前面已经介绍, 是一个可选的准备方法 .
     *                     2.调用 Observable 中的 OnSubscribe .call ( Subscriber ) .在这里, 事件发送的逻辑开始运行, 从这也可以看出,
     *                       在Rxjava 中 Observable 并不是在创建的时候就立即开始发送事件, 而是在它被订阅的时候,
     *                       即当 subscribe ( ) 方法执行的时候.
     *                     3.将传入的Subscriber 作为 Subscription 返回 . 这是为了方便 unsubscribe ( )
     *
     *  除了subscribe(Observer) 和 subscribe(Subscriber), subscribe()还定义不完整的回调,
     *  Rxjava 会自动根据定义创建出 Subscriber观察者 .形式如下
     *
     *      Action1<String> onNextAction = new Action1<String>() {
     *                  // onNext()
     *                  @Override
     *                  public void call(String s) {
     *                      Log.d(tag, s);
     *                  }
     *      };
     *       自动创建 Subscriber ，并使用 onNextAction 来定义 onNext()
     *          observable.subscribe(onNextAction)
     *      这个代码意思就是可以这样写也是订阅 观察者 :
     *      订阅 subscribe ( new Action1<String>() {
     *                       // onNext() 也就代表执行代码块
     *                       @Override
     *                       public void call(String s) {
     *                          // Log.d(tag, s);   返回来数据就可以在UI线程操作了
     *                    }
     *     });
     *
     *
     *      Action1<Throwable> onErrorAction = new Action1<Throwable>() {
     *                  // onError()   也就是代表发生异常报错时候使用
     *                  @Override
     *                  public void call(Throwable throwable) {
     *                  // Error handling
     *                  }
     *      };
     *      自动创建 Subscriber ，并使用 onNextAction 和 onErrorAction 来定义 onNext()
     *      和 onError()  observable.subscribe(onNextAction, onErrorAction);
     *      这个代码意思就是可以这样写也是订阅 观察者 :
     *      订阅 subscribe (new Action1<Throwable>() {
     *                        // onError()    也就是代表发生异常报错时候使用
     *                        @Override
     *                        public void call(Throwable throwable) {
     *                        // Error handling
     *                        }
     *      });
     *
     */
     /*    Action0 onCompletedAction = new Action0() {
                         // onCompleted()
                         @Override
                         public void call() {
                         Log.d(tag, "completed");
                     }
         };
        *//* 自动创建 Subscriber ，并使用 onNextAction、 onErrorAction 和 onCompletedAction
         来定义 onNext()、 onError() 和 onCompleted()observable.subscribe(onNextAction, onErrorAction, onCompletedAction);
          这个代码意思就是可以这样写也是订阅 观察者 :
          订阅 *//*
        Observable.(new Action0() {
                     //onCompleted()
                     @Override
                     public void call (){
                       Log.d(tag, "completed")
                     }
          }*/

    /**
     *  上面简单解释一下这段代码中出现的 Action1 和 Action0。 Action0 是 RxJava 的一个接口，它只有一个方法 call()，
     *  这个方法是无参无返回值的；由于 onCompleted() 方法也是无参无返回值的，因此 Action0 可以被当成一个包装对象，
     *  将 onCompleted() 的内容打包起来将自己作为一个参数传入 subscribe() 以实现不完整定义的回调。
     *  这样其实也可以看做将 onCompleted() 方法作为参数传进了 subscribe()，相当于其他某些语言中的『闭包』。
     *  Action1 也是一个接口，它同样只有一个方法 call(T param)，这个方法也无返回值，但有一个参数；
     *  与 Action0 同理，由于 onNext(T obj) 和 onError(Throwable error) 也是单参数无返回值的，
     *  因此 Action1 可以将 onNext(obj) 和 onError(error) 打包起来传入 subscribe() 以实现不完整定义的回调。
     *  事实上，虽然 Action0 和 Action1 在 API 中使用最广泛，
     *  但 RxJava 是提供了多个 ActionX 形式的接口 (例如 Action2, Action3) 的，它们可以被用以包装不同的无返回值的方法。
     *
     *
     *
     *
     *     注：正如前面所提到的，Observer 和 Subscriber 具有相同的角色，而且 Observer 在 subscribe()
     *     过程中最终会被转换成 Subscriber 对象，因此，从这里开始，后面的描述我将用 Subscriber 来代替 Observer ，这样更加严谨。
     *
     */

    /**
     * 场景示例
     * 将字符串数组names中的所有字符串一次打印出来
     */
    public void mPrintlnStringArray() {

        String[] names = {"wangdong", "xiaoting", "yating"};
        //说明: 用from创建被观察者 订阅 观察者 处理 打印字符串字符
        Observable.from(names).subscribe(new Action1<String>() {
            @Override
            public void call(String name) {
                Log.d(tag, name);
            }
        });
    }

    /**
     * 由id取得图片并显示
     */
    public void showImageview() {

        final int drawableRes = R.mipmap.ic_launcher;
        final ImageView imageView = new ImageView(this);
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT,
                RelativeLayout.LayoutParams.WRAP_CONTENT);
        imageView.setLayoutParams(lp);

        Observable.create(new Observable.OnSubscribe<Drawable>() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void call(Subscriber<? super Drawable> subscriber) {
                Drawable drawable = getTheme().getDrawable(drawableRes);
                subscriber.onNext(drawable);
                subscriber.onCompleted();
            }
        }).subscribe(new Observer<Drawable>() {
            @Override
            public void onCompleted() {
                Toast.makeText(RxjavaActivity.this, "Error!", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Drawable drawable) {
                imageView.setImageDrawable(drawable);
            }
        });
    }
    /**
     * 示例总结:正如上面两个列子这 创建Observable和Subscriber,再用subscribe()将它们串起来,一次RxJava的基本使用就完成
     * 非常简单,    然而 这并没有什么diao用.
     * 在RxJava的默认规则中,事件的发出和消费都是在同一个线程的,也就是说,如果只用上面的方法,实现出来的只是一个同步的观察者模式
     * .观察者模式本身的目的就是(后台处理,前台回调) 的异步机制,因此异步对于Rxjava是至关重要的,而要实现异步,则需要用Rxjava的另一个
     * 概念: Scheduler
     *
     */

    /**
     *
     * 3.线程控制--Scheduler--调度器
     *  在不指明线程情况下,RxJava遵循的是线程不变的原则,即:在哪个线程调用subscribe(),就在哪个线程产生事件:在哪个线程产生事件,就在
     *  那个线程消费事件,如果想要切换线程,就需要用到Scheduler(调度器)
     *
     *  Scheduler的 API (一)
     *
     *      在RxJava中,Scheduler --调度器,相当于现场控制器,RxJava通过它来指定每一段代码应该运行在什么样的线程.RxJava已经内置
     *      了几个Scheduler,它们已经适合大多数的使用场景
     *
     *    1.Schedulers.immediate()          :直接在当前线程运行,相当于不在指定线程. 这是默认的 Scheduler.
     *    2.Schedulers.newThread()          :总是启用新线程,并在新线程执行操作.
     *    3.Schedulers.io()                 :I/O操作(读写文件,读写数据库,网络信息交互等) 所使用的Scheduler.
     *                                       行为模式和newThread()差不多,区别在于 io()的内部实现是用一个无数量上线的线程池,可以重用
     *                                       空闲的线程,因此多数情况下io()比newThread()更有效率. 不要在计算工作放在 io()中,可以避免
     *                                       创建不必要的线程
     *    4.Schedulers.computation()        :计算所使用的Scheduler. 这个计算指的是CPU密集型计算,即不会被I/O等操作限制性能的操作,泪如
     *                                        图形的计算.这个Scheduler使用的固定的线程池,大小为CPU核数. 不要把I/O操作放在computation
     *                                        中,否则I/O操作的等待时间会浪费CPU
     *      5.AndroidScheduler.mainThread() :这个Android专用的,它指定操作将在Android主线程运行
     *
     *    有了这几个Scheduler, 就可以使用subscribeOn()和observeOn()两个方法来对线程进行控制了.
     *
     *    1.*.subscribeOn()         : 指定subscribe()订阅所发生的线程,即 Observable.OnSubscribe被激活的时所处理的线程
     *    2.*.observeOn()           : 指定Subscriber所运行在的线程 或者叫做事件消费线程
     *
     *
     */
    /**
     * 示例 :
     * 使用 了后台线程取数据,主线程显示的程序策略
     */
    public void mScheduler() {
        Observable.just(1, 2, 3, 4).subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
                .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer number) {
                        Log.d(tag, "number:" + number);
                    }
                });
    }
    /**
     * 示例2 :如果前面提到id取得图片并显示的例子,如果也加上这两句:
     */
    /**
     * 由id取得图片并显示
     */
    public void showImageview2() {

        final int drawableRes = R.mipmap.ic_launcher;
        final ImageView imageView = new ImageView(this);
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT,
                RelativeLayout.LayoutParams.WRAP_CONTENT);
        imageView.setLayoutParams(lp);

        Observable.create(new Observable.OnSubscribe<Drawable>() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void call(Subscriber<? super Drawable> subscriber) {
                Drawable drawable = getTheme().getDrawable(drawableRes);
                subscriber.onNext(drawable);
                subscriber.onCompleted();
            }
        }).subscribeOn(Schedulers.io()) //指定 subscribe() 发生在 IO 线程.
                .observeOn(AndroidSchedulers.mainThread()) //指定 Subscriber 的回调发生在主线程
                .subscribe(new Observer<Drawable>() {
                    @Override
                    public void onCompleted() {
                        Toast.makeText(RxjavaActivity.this, "Error!", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(Drawable drawable) {
                        imageView.setImageDrawable(drawable);
                    }
                });
    }

    /**
     * Scheduler 的原理(一)
     * <p>
     * Schedule API很方便,也很神奇(加上一句话就把线程切换了,怎么做到的?
     * 因为它的原理是一下节<<变换>> 的原理作为基础的
     * <p>
     * <p>
     * <p>
     * 4 .变换
     * 终于要到牛逼的地方了,不管你激动不激动,反正我是激动了
     * RxJava 提供了对 事件序列进行变换的支持,这是他的核心功能之一
     * 也是大多数人说 :"RxJava真是好用了" 的最大原因
     * 所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列.
     * <p>
     * 1)API
     * <p>
     * 首先看一个map () 例子
     */
    public void mMap() {
        //被观察者 .使用了just( 多参数的形式)
        Observable.just("images/logo.png") //输入类型 String
                .map(new Func1<String, Bitmap>() {
                    @Override
                    public Bitmap call(String filePath) {//参数类型 String
                        //  return getBitmapFromPath(filePath);//返回类型 Bitmap
                        return null;
                    }
                }).subscribe(new Action1<Bitmap>() {
            @Override
            public void call(Bitmap bitmap) { //参数类型 Bitmap
//                showBitmap(bitmap);
            }
        });

    }

    /**
     * 这里出现了一个叫做 Func1 的类。它和 Action1 非常相似，
     * 也是 RxJava 的一个接口，用于包装含有一个参数的方法。
     * Func1 和 Action 的区别在于， Func1 包装的是有返回值的方法。
     * 另外，和 ActionX 一样， FuncX 也有多个，用于不同参数个数的方法。
     * FuncX 和 ActionX 的区别在 FuncX 包装的是有返回值的方法。
     * <p>
     * 可以看到，map() 方法将参数中的 String 对象转换成一个 Bitmap 对象后返回，而在经过 map() 方法后，
     * 事件的参数类型也由 String 转为了 Bitmap。这种直接变换对象并返回的，是最常见的也最容易理解的变换。
     * 不过 RxJava 的变换远不止这样，它不仅可以针对事件对象，还可以针对整个事件队列，这使得 RxJava 变得非常灵活。我列举几个常用的变换：
     * <p>
     * map () :事件对象的直接变换,具体功能上面已经介绍过了,它是RxJava最常用的变换
     * <p>
     * flatMap(): 这是一个很有用但非常难理解的变换，因此我决定花多些篇幅来介绍它。
     * 首先假设这么一种需求：假设有一个数据结构『学生』，现在需要打印出一组学生的名字。实现方式很简单：
     */
    public void mflatmap() {
        Student[] students = {new Student().setName("小明"), new Student().setName("小花")};
       /* Subscriber<String> subscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(String s) {

                Log.d(tag, s);

            }
        };
        Observable.from(students).map(new Func1<Student, String>() {
            @Override
            public String call(Student student) {
                return student.getName();
            }
        }).subscribe(subscriber);*/


        /**
         * 很简单。那么再假设：如果要打印出每个学生所需要修的所有课程的名称呢？
         * （需求的区别在于，每个学生只有一个名字，但却有多个课程。）首先可以这样实现：
         */

        /*Subscriber<Student> subscriber = new Subscriber<Student>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
            }

            @Override
            public void onNext(Student student) {
                List<Course> courses = student.getCourses();
                for (int i = 0; i < courses.size(); i++) {
                    Course course = courses.get(i);
                    Log.d(tag, course.getName());
                }
            }
        };
        Observable.from(students).
                subscribe(subscriber);*/

        /**
         * 依然很简单。那么如果我不想在 Subscriber 中使用 for 循环，而是希望 Subscriber
         * 中直接传入单个的 Course 对象呢（这对于代码复用很重要）？
         * 用 map() 显然是不行的，因为 map() 是一对一的转化，而我现在的要求是一对多的转化。
         * 那怎么才能把一个 Student 转化成多个 Course 呢？
         *
         * 这个时候，就需要用 flatMap() 了：
         */

        Subscriber<Course> subscriber = new Subscriber<Course>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
            }

            @Override
            public void onNext(Course course) {
                Log.d(tag, course.getName());
            }
        };
        Observable.from(students).flatMap(new Func1<Student, Observable<Course>>() {
            @Override
            public Observable<Course> call(Student student) {
                return Observable.from(student.getCourses());
            }
        }).subscribe(subscriber);
        /**
         *
         * 从上面的代码可以看出， flatMap() 和 map() 有一个相同点：它也是把传入的参数转化之后返回另一个对象。
         * 但需要注意，和 map() 不同的是， flatMap() 中返回的是个 Observable 对象，
         * 并且这个 Observable 对象并不是被直接发送到了 Subscriber 的回调方法中。
         * flatMap() 的原理是这样的：
         *          1. 使用传入的事件对象创建一个 Observable 对象；
         *          2. 并不发送这个 Observable, 而是将它激活，于是它开始发送事件；
         *          3. 每一个创建出来的 Observable 发送的事件，都被汇入同一个 Observable ，
         *              而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法。
         *   这三个步骤，把事件拆成了两级，通过一组新创建的 Observable 将初始的对象『铺平』之后通过统一路径分发了下去。
         *   而这个『铺平』就是 flatMap() 所谓的 flat。
         *
         *   扩展：由于可以在嵌套的 Observable 中添加异步代码， flatMap() 也常用于嵌套的异步操作，例如嵌套的网络请求。示例代码（Retrofit + RxJava）：
         */
        /*networkClient.token() // 返回 Observable<String>，在订阅时请求 token，并在响应后发送 token
                .flatMap(new Func1<String, Observable<Messages>>() {
                    @Override
                    public Observable<Messages> call(String token) { // 返回 Observable<Messages>，在订阅时请求消息列表，并在响应后发送请求到的消息列表
                        return networkClient.messages();
                    }
                })
                .subscribe(new Action1<Messages>() {
                    @Override
                    public void call(Messages messages) {  // 处理显示消息列表
                        showMessages(messages);
                    }
                });*/
        /**
         * 传统的嵌套请求需要使用嵌套的 Callback 来实现。而通过 flatMap() ，可以把嵌套的请求写在一条链中，从而保持程序逻辑的清晰。
         *
         *  throttleFirst(): 在每次事件触发后的一定时间间隔内丢弃新的事件。常用作去抖动过滤，例如按钮的点击监听器：
         *         RxView.clickEvents(button) // RxBinding 代码，后面的文章有解释
         *          .throttleFirst(500, TimeUnit.MILLISECONDS) // 设置防抖间隔为 500ms.subscribe(subscriber);
         *          妈妈再也不怕我的用户手抖点开两个重复的界面啦。
         *
         *          此外， RxJava 还提供很多便捷的方法来实现事件序列的变换，这里就不一一举例了。
         */

        /**
         * 2) 变换的原理：lift()
         *      这些变换虽然功能各有不同，但实质上都是针对事件序列的处理和再发送。
         *      而在 RxJava 的内部，它们是基于同一个基础的变换方法：
         *      lift(Operator)。首先看一下 lift() 的内部实现（仅核心代码）：
         *
         *  // 注意：这不是 lift() 的源码，而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
         *  // 如果需要看源码，可以去 RxJava 的 GitHub 仓库下载。
         *
         *  //它生成了一个新的 Observable 并返回
         *  public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
         *      return Observable.create(new OnSubscribe<R>() {//而且创建新 Observable 所用的参数 OnSubscribe 的回调方法 call()
         *          @Override
         *          public void call(Subscriber subscriber) {
         *              Subscriber newSubscriber = operator.call(subscriber);
         *              newSubscriber.onStart();
         *              onSubscribe.call(newSubscriber);
         *          }
         *      });
         *  }
         *
         *  这段代码很有意思：它生成了一个新的 Observable 并返回，而且创建新 Observable 所用的参数 OnSubscribe 的回调方法 call()
         *  中的实现竟然看起来和前面讲过的 Observable.subscribe() 一样！
         *  然而它们并不一样哟~不一样的地方关键就在于第二行 onSubscribe.call(subscriber) 中的 onSubscribe 所指代的对象不同
         *  （高能预警：接下来的几句话可能会导致身体的严重不适）——
         *
         * subscribe() 中这句话的 onSubscribe 指的是 Observable 中的 onSubscribe 对象，这个没有问题，但是 lift() 之后的情况就复杂了点。
         * 当含有 lift() 时：
         * 1.lift() 创建了一个 Observable 后，加上之前的原始 Observable，已经有两个 Observable 了；
         * //解释一下王东个人认为另一个Observable所以指的是外部调用lift()的Observable
         * 2.而同样地，新 Observable 里的新 OnSubscribe 加上之前的原始 Observable 中的原始 OnSubscribe，也就有了两个 OnSubscribe；
         * 3.当用户调用经过 lift() 后的 Observable 的 subscribe() 的时候，使用的是 lift() 所返回的新的 Observable ，
         *  于是它所触发的 onSubscribe.call(subscriber)，也是用的新 Observable 中的新 OnSubscribe，即在 lift() 中生成的那个 OnSubscribe；
         * 4.而这个新 OnSubscribe 的 call() 方法中的 onSubscribe ，就是指的原始 Observable 中的原始 OnSubscribe ，
         * 在这个 call() 方法里，新 OnSubscribe 利用 operator.call(subscriber) 生成了一个新的 Subscriber
         * （Operator 就是在这里，通过自己的 call() 方法将新 Subscriber 和原始 Subscriber 进行关联，并插入自己的『变换』代码以实现变换），
         * 然后利用这个新 Subscriber 向原始 Observable 进行订阅。
         * 这样就实现了 lift() 过程，有点像一种代理机制，通过事件拦截和处理实现事件序列的变换。
         *
         *
         * 精简掉细节的话，也可以这么说：在 Observable 执行了 lift(Operator) 方法之后，
         * 会返回一个新的 Observable，这个新的 Observable 会像一个代理一样，负责接收原始的 Observable 发出的事件，
         * 并在处理后发送给 Subscriber。
         */

        /**
         * 而且创建新 Observable 所用的参数 OnSubscribe 的回调方法 call()
         */
       /* Observable.lift(new Observable.Operator<String, Integer>() {
            // 将事件序列中的 Integer 对象转换为 String 对象
            @Override
            public Subscriber<? super Integer> call(final Subscriber<? super String> subscriber) {
                return new Subscriber<Integer>() {
                    @Override
                    public void onNext(Integer integer) {
                        subscriber.onNext("" + integer);
                    }

                    @Override
                    public void onCompleted() {
                        subscriber.onCompleted();
                    }

                    @Override
                    public void onError(Throwable e) {
                        subscriber.onError(e);
                    }
                };
            }
        });*/
        /**
         *
         * 讲述 lift() 的原理只是为了让你更好地了解 RxJava ，从而可以更好地使用它。然而不管你是否理解了 lift() 的原理，
         * RxJava 都不建议开发者自定义 Operator 来直接使用 lift()，而是建议尽量使用已有的 lift() 包装方法（如 map() flatMap() 等）
         * 进行组合来实现需求，因为直接使用 lift() 非常容易发生一些难以发现的错误
         */

  /** 3) compose: 对 Observable 整体的变换
        除了 lift() 之外， Observable 还有一个变换方法叫做 compose(Transformer)。它和 lift() 的区别在于，
        lift() 是针对事件项和事件序列的，而 compose() 是针对 Observable 自身进行变换。
   举个例子，假设在程序中有多个 Observable ，并且他们都需要应用一组相同的 lift() 变换。你可以这么写：

    observable1
    .lift1()
     .lift2()
     .lift3()
     .lift4()
     .subscribe(subscriber1);
     observable2
   .lift1()
   .lift2()
   .lift3()
   .lift4()
   .subscribe(subscriber2);
   observable3
   .lift1()
   .lift2()
   .lift3()
   .lift4()
   .subscribe(subscriber3);
   observable4
   .lift1()
   .lift2()
   .lift3()
   .lift4()
   .subscribe(subscriber1);

        你觉得这样太不软件工程了，于是你改成了这样：

private Observable liftAll(Observable observable) {
   return observable
   .lift1()
   .lift2()
   .lift3()
   .lift4();
   }...


   liftAll(observable1).subscribe(subscriber1);
   liftAll(observable2).subscribe(subscriber2);
   liftAll(observable3).subscribe(subscriber3);
   liftAll(observable4).subscribe(subscriber4);
        可读性、可维护性都提高了。可是 Observable 被一个方法包起来，这种方式对于 Observale 的灵活性似乎还是增添了那么点限制。
   怎么办？这个时候，就应该用 compose() 来解决了：

public class LiftAllTransformer implements Observable.Transformer<Integer, String> {
   @Override
   public Observable<String> call(Observable<Integer> observable) {
   return observable
                .lift1()
                .lift2()
                .lift3()
                .lift4();
   }
   }...

   Transformer liftAll = new LiftAllTransformer();
   observable1.compose(liftAll)
   .subscribe(subscriber1);
   observable2.compose(liftAll).subscribe(subscriber2);
   observable3.compose(liftAll).subscribe(subscriber3);
   observable4.compose(liftAll).subscribe(subscriber4);
        像上面这样，使用 compose() 方法，Observable 可以利用传入的 Transformer 对象的 call 方法直接对自身进行处理，
    也就不必被包在方法的里面了。

        compose() 的原理比较简单，不附图喽。
        */

  /**
   * 5. 线程控制：Scheduler (二)
   * 除了灵活的变换，RxJava 另一个牛逼的地方，就是线程的自由控制。
   *
   * 1) Scheduler 的 API (二)
   *    前面讲到了，可以利用 subscribeOn() 结合 observeOn() 来实现线程控制，让事件的产生和消费发生在不同的线程。
   *    可是在了解了 map() flatMap() 等变换方法后，有些好事的（其实就是当初刚接触 RxJava 时的我）就问了：能不能多切换几次线程？
   *
   * 答案是：能。因为 observeOn() 指定的是 Subscriber 的线程，
   * 而这个 Subscriber 并不是（严格说应该为『不一定是』，但这里不妨理解为『不是』）subscribe() 参数中的 Subscriber ，
   * 而是 observeOn() 执行时的当前 Observable 所对应的 Subscriber ，即它的直接下级 Subscriber 。
   * 换句话说，observeOn() 指定的是它之后的操作所在的线程。
   * 因此如果有多次切换线程的需求，只要在每个想要切换线程的位置调用一次 observeOn() 即可。上代码：
   */
   /* Observable.just(1, 2, 3, 4) // IO 线程，由 subscribeOn() 指定
             .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.newThread())
            .map(mapOperator) // 新线程，由 observeOn() 指定
            .observeOn(Schedulers.io())
            .map(mapOperator2) // IO 线程，由 observeOn() 指定
            .observeOn(AndroidSchedulers.mainThread)
            .subscribe(subscriber);  // Android 主线程，由 observeOn() 指定*/

   /** observeOn() : 如上，通过 observeOn() 的多次调用，程序实现了线程的多次切换。
   *
   * subscribeOn() : 不过，不同于 observeOn() ， subscribeOn() 的位置放在哪里都可以，但它是只能调用一次的。
   *
   * 又有好事的（其实还是当初的我）问了：如果我非要调用多次 subscribeOn() 呢？会有什么效果？
   *
   * 这个问题先放着，我们还是从 RxJava 线程控制的原理说起吧。
   *
   *
   *
   *
   */

   /**
    * 3) 延伸：doOnSubscribe()
    *
    * 然而，虽然超过一个的 subscribeOn() 对事件处理的流程没有影响，但在流程之前却是可以利用的。
    *
    * 在前面讲 Subscriber 的时候，提到过 Subscriber 的 onStart() 可以用作流程开始前的初始化。
    *
    * 然而 onStart() 由于在 subscribe() 发生时就被调用了，因此不能指定线程，
    *
    * 而是只能执行在 subscribe() 被调用时的线程。
    * 这就导致如果 onStart() 中含有对线程有要求的代码（例如在界面上显示一个 ProgressBar，这必须在主线程执行），
    * 将会有线程非法的风险，因为有时你无法预测 subscribe() 将会在什么线程执行。
    *
    * 而与 Subscriber.onStart() 相对应的，有一个方法 Observable.doOnSubscribe() 。
    * 它和 Subscriber.onStart() 同样是在 subscribe() 调用后而且在事件发送前执行，但区别在于它可以指定线程。
    * 默认情况下， doOnSubscribe() 执行在 subscribe() 发生的线程；
    * 而如果在 doOnSubscribe() 之后有 subscribeOn() 的话，它将执行在离它最近的 subscribeOn() 所指定的线程。
    *
    * 示例代码：
    */

     /*Observable.create(onSubscribe)
             .subscribeOn(Schedulers.io())
             .doOnSubscribe(new Action0() {
                 @Override
                 public void call() {
                     progressBar.setVisibility(View.VISIBLE); // 需要在主线程执行
                    }
             })
             .subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程
             .observeOn(AndroidSchedulers.mainThread())
             .subscribe(subscriber);*/

    //如上，在 doOnSubscribe()的后面跟一个 subscribeOn() ，就能指定准备工作的线程了。

    /**
    *RxJava 的适用场景和使用方式
     * 1. 与 Retrofit 的结合
     * Retrofit 是 Square 的一个著名的网络请求库。没有用过 Retrofit 的可以选择跳过这一小节也没关系，
     * 我举的每种场景都只是个例子，而且例子之间并无前后关联，只是个抛砖引玉的作用，所以你跳过这里看别的场景也可以的。
     *
     * Retrofit 除了提供了传统的 Callback 形式的 API，还有 RxJava 版本的 Observable 形式 API。
     * 下面我用对比的方式来介绍 Retrofit 的 RxJava 版 API 和传统版本的区别。
     *
     * 以获取一个 User 对象的接口作为例子。使用Retrofit 的传统 API，你可以用这样的方式来定义请求：
     *
     * @GET("/user")
     * public void getUser(@Query("userId") String userId, Callback<User> callback);
     *
     * 在程序的构建过程中， Retrofit 会把自动把方法实现并生成代码，然后开发者就可以利用下面的方法来获取特定用户并处理响应：
     *
     * getUser(userId, new Callback<User>() {
     * @Override
     * public void success(User user) {
     * userView.setUser(user);
     * }
     * @Override
     * public void failure(RetrofitError error) {        // Error handling        ...    }};
     *
     * 而使用 RxJava 形式的 API，定义同样的请求是这样的：
     *
     * @GET("/user")public Observable<User> getUser(@Query("userId") String userId);
     *
     * 使用的时候是这样的：
     *
     * getUser(userId)
     * .observeOn(AndroidSchedulers.mainThread())
     * .subscribe(new Observer<User>() {
     * @Override
     * public void onNext(User user) {
     * userView.setUser(user);
     * }
     * @Override
     * public void onCompleted() {        }
     * @Override
     * public void onError(Throwable error) {
     * // Error handling            ...        }    });
     *
     * 看到区别了吗？
     *
     * 当 RxJava 形式的时候，Retrofit 把请求封装进 Observable ，在请求结束后调用 onNext() 或在请求失败后调用 onError()。
     *
     * 对比来看， Callback 形式和 Observable 形式长得不太一样，但本质都差不多，
     * 而且在细节上 Observable 形式似乎还比 Callback 形式要差点。
     * 那 Retrofit 为什么还要提供 RxJava 的支持呢？
     *
     * 因为它好用啊！从这个例子看不出来是因为这只是最简单的情况。
     * 而一旦情景复杂起来， Callback 形式马上就会开始让人头疼。比如：
     *
     * 假设这么一种情况：你的程序取到的 User 并不应该直接显示，而是需要先与数据库中的数据进行比对和修正后再显示。
     * 使用 Callback 方式大概可以这么写：
     *
     * getUser(userId, new Callback<User>() {
     * @Override
     * public void success(User user) {
     * processUser(user); // 尝试修正 User 数据
     * userView.setUser(user);    }
     * @Override
     * public void failure(RetrofitError error) {        // Error handling        ...    }};
     *
     * 有问题吗？
     *
     * 很简便，但不要这样做。为什么？因为这样做会影响性能。数据库的操作很重，
     * 一次读写操作花费 10~20ms 是很常见的，这样的耗时很容易造成界面的卡顿。
     * 所以通常情况下，如果可以的话一定要避免在主线程中处理数据库。所以为了提升性能，这段代码可以优化一下：
     *
     * getUser(userId, new Callback<User>() {
     * @Override
     * public void success(User user) {
     * new Thread() {
     * @Override
     * public void run() {
     * processUser(user); // 尝试修正 User 数据
     * runOnUiThread(new Runnable() { // 切回 UI 线程
     * @Override
     * public void run() {
     * userView.setUser(user);
     * }                });            })
     * .start();    }
     * @Override
     * public void failure(RetrofitError error) {
     * // Error handling        ...    }};
     *
     * 性能问题解决，但……这代码实在是太乱了，迷之缩进啊！杂乱的代码往往不仅仅是美观问题，因为代码越乱往往就越难读懂，
     * 而如果项目中充斥着杂乱的代码，无疑会降低代码的可读性，造成团队开发效率的降低和出错率的升高。
     *
     * 这时候，如果用 RxJava 的形式，就好办多了。 RxJava 形式的代码是这样的：
     *
     * getUser(userId)
     * .doOnNext(new Action1<User>() {
     * @Override
     * public void call(User user) {
     * processUser(user);        })
     * .observeOn(AndroidSchedulers.mainThread())
     * .subscribe(new Observer<User>() {
     * @Override
     * public void onNext(User user) {
     * userView.setUser(user);        }
     * @Override
     * public void onCompleted() {        }
     * @Override
     * public void onError(Throwable error) {
     * // Error handling            ...        }    });
     *
     * 后台代码和前台代码全都写在一条链中，明显清晰了很多。
     *
     * 再举一个例子：假设 /user 接口并不能直接访问，而需要填入一个在线获取的 token ，代码应该怎么写？
     *
     * Callback 方式，可以使用嵌套的 Callback：
     *
     * @GET("/token")
     * public void getToken(Callback<String> callback);
     * @GET("/user")public void getUser(@Query("token") String token, @Query("userId") String userId, Callback<User> callback);...
     * getToken(new Callback<String>() {
     * @Override
     * public void success(String token) {
     * getUser(token, userId, new Callback<User>() {
     * @Override
     * public void success(User user) {
     * userView.setUser(user);            }
     * @Override
     * public void failure(RetrofitError error) {
     * // Error handling                ...            }        };    }
     * @Override
     * public void failure(RetrofitError error) {        // Error handling        ...    }});
     *
     *
     * 倒是没有什么性能问题，可是迷之缩进毁一生，你懂我也懂，做过大项目的人应该更懂。
     *
     * 而使用 RxJava 的话，代码是这样的：
     *
     * @GET("/token")public Observable<String> getToken();
     * @GET("/user")public Observable<User> getUser(@Query("token") String token, @Query("userId") String userId);
     * ...getToken()
     * .flatMap(new Func1<String, Observable<User>>() {
     * @Override
     * public Observable<User> onNext(String token) {
     * return getUser(token, userId);        })
     * .observeOn(AndroidSchedulers.mainThread())
     * .subscribe(new Observer<User>() {
     * @Override
     * public void onNext(User user) {
     * userView.setUser(user);        }
     * @Override
     * public void onCompleted() {        }
     * @Override
     * public void onError(Throwable error) {
     * // Error handling            ...        }    });
     *
     * 用一个 flatMap() 就搞定了逻辑，依然是一条链。看着就很爽，是吧？
     *
     * 2016/03/31 更新，加上我写的一个 Sample 项目：
     * rengwuxian RxJava Samples
     *
     * 好，Retrofit 部分就到这里。
     *
     * 2. RxBinding
     * RxBinding 是 Jake Wharton 的一个开源库，它提供了一套在 Android 平台上的基于 RxJava 的 Binding API。
     * 所谓 Binding，就是类似设置 OnClickListener 、设置 TextWatcher 这样的注册绑定对象的 API。
     *
     * 举个设置点击监听的例子。使用 RxBinding ，可以把事件监听用这样的方法来设置：
     *
     * Button button = ...;
     * RxView.clickEvents(button) // 以 Observable 形式来反馈点击事件
     * .subscribe(new Action1<ViewClickEvent>() {
     * @Override
     * public void call(ViewClickEvent event) {
     * // Click handling        }    });
     *
     * 看起来除了形式变了没什么区别，实质上也是这样。甚至如果你看一下它的源码，你会发现它连实现都没什么惊喜：
     * 它的内部是直接用一个包裹着的 setOnClickListener() 来实现的。然而，仅仅这一个形式的改变，
     * 却恰好就是 RxBinding 的目的：扩展性。通过 RxBinding 把点击监听转换成 Observable 之后，
     * 就有了对它进行扩展的可能。扩展的方式有很多，根据需求而定。一个例子是前面提到过的 throttleFirst() ，
     * 用于去抖动，也就是消除手抖导致的快速连环点击：
     *
     * RxView.clickEvents(button)
     * .throttleFirst(500, TimeUnit.MILLISECONDS)
     * .subscribe(clickAction);
     * 如果想对 RxBinding 有更多了解，可以去它的 GitHub 项目 下面看看。
     *
     * 3. 各种异步操作
     * 前面举的 Retrofit 和 RxBinding 的例子，是两个可以提供现成的 Observable 的库。
     * 而如果你有某些异步操作无法用这些库来自动生成 Observable，也完全可以自己写。
     * 例如数据库的读写、大图片的载入、文件压缩/解压等各种需要放在后台工作的耗时操作，
     * 都可以用 RxJava 来实现，有了之前几章的例子，这里应该不用再举例了。
     *
     * 4. RxBus
     * RxBus 名字看起来像一个库，但它并不是一个库，而是一种模式，它的思想是使用 RxJava 来实现了 EventBus ，
     * 而让你不再需要使用 Otto 或者 GreenRobot 的 EventBus。至于什么是 RxBus，可以看这篇文章。顺便说一句，
     * Flipboard 已经用 RxBus 替换掉了 Otto ，目前为止没有不良反应。
     *
     * 最后
     * 对于 Android 开发者来说， RxJava 是一个很难上手的库，因为它对于 Android 开发者来说有太多陌生的概念了。
     * 可是它真的很牛逼。因此，我写了这篇《给 Android 开发者的 RxJava 详解》，
     * 希望能给始终搞不明白什么是 RxJava 的人一些入门的指引，
     * 或者能让正在使用 RxJava 但仍然心存疑惑的人看到一些更深入的解析。无论如何，
     * 只要能给各位同为 Android 工程师的你们提供一些帮助，这篇文章的目的就达到了。
     *
     * 再次感谢对这篇文章的产出提供支持的各位：
     * 技术支持：流火枫林
     * 内测读者：代码家、鲍永章、drakeet、马琳、有时放纵、程序亦非猿、大头鬼、XZoomEye、席德雨、
     * TCahead、Tiiime、Ailurus、宅学长、妖孽、大大大大大臣哥、NicodeLee
     * 赞助方：周伯通招聘是他们让我的文章能够以不那么丑陋的样子出现在大家面前。
     *
     * 关于作者
     * 朱凯（扔物线），Flipboard 北京 Android 工程师。
    *
    *
    */


    }

}
